package top.zhangjianyong.tools.indicator.strategy.impl;

import org.springframework.stereotype.Component;
import top.zhangjianyong.tools.entity.ETFData;
import top.zhangjianyong.tools.indicator.context.IndicatorContext;
import top.zhangjianyong.tools.indicator.model.TechnicalIndicatorResult;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * 波动率指标计算器
 * 计算5日、10日、20日滚动标准差（年化）（vol_5、vol_10、vol_20）
 *
 * @author zhangjianyong
 * @date 2024/01/01
 */
@Component
public class VolatilityIndicator extends AbstractIndicator {

    private static final String INDICATOR_NAME = "VOLATILITY";
    private static final int TRADING_DAYS_PER_YEAR = 252; // 年交易日数

    @Override
    public String getName() {
        return INDICATOR_NAME;
    }

    @Override
    public int getMinDataSize() {
        return 20; // 最大周期是20日
    }

    @Override
    protected TechnicalIndicatorResult doCalculate(IndicatorContext context) {
        List<ETFData> dataList = context.getDataList();

        TechnicalIndicatorResult result = TechnicalIndicatorResult.success(getName());

        // 计算5日波动率（年化）
        BigDecimal vol5 = calculateVolatility(dataList, 5);
        if (vol5 != null) {
            result.addValue("vol_5", vol5.setScale(4, RoundingMode.HALF_UP));
        }

        // 计算10日波动率（年化）
        BigDecimal vol10 = calculateVolatility(dataList, 10);
        if (vol10 != null) {
            result.addValue("vol_10", vol10.setScale(4, RoundingMode.HALF_UP));
        }

        // 计算20日波动率（年化）
        BigDecimal vol20 = calculateVolatility(dataList, 20);
        if (vol20 != null) {
            result.addValue("vol_20", vol20.setScale(4, RoundingMode.HALF_UP));
        }

        return result;
    }

    /**
     * 计算指定周期的波动率（年化）
     * 波动率 = 收益率标准差 * √(年交易日数)
     *
     * @param dataList K线数据列表
     * @param period   周期
     * @return 年化波动率（百分比）
     */
    private BigDecimal calculateVolatility(List<ETFData> dataList, int period) {
        if (dataList.size() < period + 1) {
            return null;
        }

        // 计算收益率序列
        List<BigDecimal> returns = new java.util.ArrayList<>();
        for (int i = dataList.size() - period; i < dataList.size(); i++) {
            if (i == 0) {
                continue;
            }
            ETFData current = dataList.get(i);
            ETFData previous = dataList.get(i - 1);

            BigDecimal previousPrice = previous.getValue();
            if (previousPrice.compareTo(BigDecimal.ZERO) == 0) {
                continue;
            }

            BigDecimal returnRate = current.getValue().subtract(previousPrice)
                .divide(previousPrice, 8, RoundingMode.HALF_UP);
            returns.add(returnRate);
        }

        if (returns.isEmpty()) {
            return null;
        }

        // 计算收益率均值
        BigDecimal meanReturn = BigDecimal.ZERO;
        for (BigDecimal ret : returns) {
            meanReturn = meanReturn.add(ret);
        }
        meanReturn = meanReturn.divide(BigDecimal.valueOf(returns.size()), 8, RoundingMode.HALF_UP);

        // 计算标准差
        BigDecimal sumSquaredDiff = BigDecimal.ZERO;
        for (BigDecimal ret : returns) {
            BigDecimal diff = ret.subtract(meanReturn);
            sumSquaredDiff = sumSquaredDiff.add(diff.multiply(diff));
        }

        BigDecimal variance = sumSquaredDiff.divide(BigDecimal.valueOf(returns.size()), 8, RoundingMode.HALF_UP);
        double stdDev = Math.sqrt(variance.doubleValue());

        // 年化波动率 = 标准差 * √(年交易日数) * 100
        double annualizedVol = stdDev * Math.sqrt(TRADING_DAYS_PER_YEAR) * 100;

        return BigDecimal.valueOf(annualizedVol);
    }
}
